/*******************************************************************************
 * (c) Copyright 2008-2017 Microsemi SoC Products Group. All rights reserved.
 *
 * CorePWM driver API.
 *
 * SVN $Revision: 8935 $
 * SVN $Date: 2017-03-31 14:01:28 +0530 (Fri, 31 Mar 2017) $
 */
/*=========================================================================*//**
 @mainpage CorePWM Bare Metal Driver.

 @section intro_sec Introduction
 The CorePWM hardware IP which includes up to 16 pulse width modulated (PWM)
 outputs and up to 16 tachometer inputs. The CorePWM bare metal software
 driver is designed for use in systems with no operating system.

 The CorePWM driver provides:
 - Functions to control the duty cycle of each independent PWM output. The
 duty cycle control functions are identical for both the General Purpose
 PWM and Low Ripple DAC modes of CorePWM.
 - A function to control the positive and negative edges of each independent
 PWM output. This function can only be used for CorePWM outputs configured
 as General Purpose PWM. This function is useful for controlling the phase
 between different PWM outputs.
 - A function to generate left, centre or right aligned PWM output waveforms.
 - Functions to enable and disable synchronous update of the PWM output
 waveforms.
 - Functions to enable and disable pulse stretching of the PWM output waveforms.
 - Functions to configure and control the tachometer and measure the period of
 tachometer input signals.
 - Functions to control tachometer interrupts.

 @section driver_configuration Driver Configuration
 The CorePWM driver is configured through calls to the PWM_init() function for
 each CorePWM instance in the hardware design. The configuration parameters
 include the CorePWM hardware instance base address and other runtime
 parameters, such as the PWM clock prescale and period.
 No CorePWM hardware configuration parameters are used by the driver, apart
 from the CorePWM hardware instance base address. Hence, no additional
 configuration files are required to use the driver.

 Configured PWM Register Widths
 Each CorePWM instance in the hardware design is configured for the width of the
 APB data bus, by the APB_DWIDTH configuration parameter. This parameter also
 configures the width of CorePWM抯 PRESCALE, PERIOD, PWMx_POSEDGE, PWMx_NEGEDGE
 and DACx_LEVELOUT registers. The CorePWM driver抯 PWM_init(),
 PWM_set_duty_cycle(), PWM_set_edges() and PWM_generate_aligned_wave() functions
 write values to these registers via one or more of the parameters prescale,
 period, duty_cycle, pos_edge or neg_edge � all of type uint32_t. It is your
 responsibility to ensure that the values passed by these parameters are within
 the range 0 to (2^APB_DWIDTH - 1), where APB_DWIDTH is 8, 16 or 32 dependent
 upon your CorePWM hardware configuration, The return value from the
 PWM_get_duty_cycle() function is also within the range 0 to (2^APB_DWIDTH - 1).

 Note: Failure to keep the prescale, period, duty_cycle, pos_edge and neg_edge
 parameter values within the range 0 to (2^APB_DWIDTH - 1) will result
 in unintended CorePWM register settings.

 Fixed PWM Period or Prescale Register Values
 The prescale and period parameter values passed to the PWM_init() function may
 not have any effect if fixed values were selected for the PRESCALE and PERIOD
 registers in the hardware configuration of CorePWM. When fixed values are
 selected for these registers, the driver cannot overwrite the fixed values.

 Fixed PWM Positive or Negative Edge Register Values
 The pos_edge and neg_edge parameter values passed to the PWM_set_edges()
 function, and the duty_cycle parameter value passed to the PWM_set_duty_cycle()
 and PWM_generate_aligned_wave() functions, may not have the desired effect if
 fixed values were selected for the PWMx_POSEDGE (positive edge) or
 PWMx_NEGEDGE (negative edge) registers in the hardware configuration of
 CorePWM. When fixed values are selected for these registers, the driver cannot
 overwrite the fixed values.

 Synchronized Update of PWM Output Waveforms
 The configuration of the CorePWM instance in the hardware design must enable
 the shadow update register for each PWM channel that requires synchronous output
 waveform updates. The PWM_enable_synch_update() and PWM_disable_synch_update()
 functions will only affect PWM channels that have their shadow update registers
 enabled in hardware.

 @section theory_op Theory of Operation
 The CorePWM software driver is designed to allow the control of multiple
 instances of CorePWM. Each instance of CorePWM in the hardware design is
 associated with a single instance of the pwm_instance_t structure in the
 software.
 You need to allocate memory for one unique pwm_instance_t structure instance
 for each CorePWM hardware instance.The contents of these data structures are
 initialized during calls to function PWM_init(). A pointer to the structure
 is passed to subsequent driver functions in order to identify the CorePWM
 hardware instance you wish to perform the requested operation on.

 Note: Do not attempt to directly manipulate the content of pwm_instance_t
 structures. This structure is only intended to be modified by the driver
 function.

 Initialization
 The PWM granularity is configured through the PWM_init() function prescale
 parameter. The PWM granularity specifies the resolution of the PWM output
 waveforms for the targeted CorePWM instance. It is also sometimes called the
 PWM period count time base. It is defined by the following equation:
 PWM_GRANULARITY = SYS_CLOCK_PERIOD * ( prescale + 1 )
 Where SYS_CLOCK_PERIOD is the period of the system clock used to clock the
 CorePWM hardware instance and prescale is the value of the prescale parameter
 passed to function PWM_init().
 The PWM period is configured through the PWM_init() function period parameter.
 It specifies the period of the PWM output waveforms for the targeted CorePWM
 instance. The PWM period is defined by the following equation:
 PWM_PERIOD = PWM_GRANULARITY * ( period + 1 )

 Note: The prescale and period values passed to the PWM_init() function may not
 have any effect if fixed values were selected for the prescale and period
 in the hardware configuration of CorePWM.

 Note: The prescale and period parameters are not relevant to any PWM outputs
 that were configured for Low Ripple DAC mode in the hardware configuration
 of CorePWM. In this mode, their only role is in setting the interval between
 synchronized register updates when the shadow register is enabled for the
 PWM output.

 PWM Output Control
 The waveform for each PWM output is specified through calls to the
 PWM_set_duty_cycle() or PWM_set_edges() functions. Each PWM output is configured
 as either a General Purpose PWM output or a Low Ripple DAC output in the hardware
 configuration of CorePWM. In General Purpose PWM mode, either of the
 PWM_set_duty_cycle() or PWM_set_edges() functions may be used to specify the PWM
 output waveform. In Low Ripple DAC mode, only the PWM_set_duty_cycle() function
 may be used to specify the PWM output waveform. The duty cycle of the PWM can be
 read by calling PWM_get_duty_cyle().
 The waveform alignment of General Purpose PWM outputs can be set by calling
 PWM_generate_aligned_wave().
 The PWM_enable_synch_update() function is used to enable the synchronous update
 of a selected group of PWM channels. The PWM_disable_synch_update() is used to
 terminate the synchronous update cycle after at least one PWM period has elapsed.
 In synchronous mode the channel output waveforms are updated at the beginning of
 the PWM period, which is useful for motor control and can be used to keep a
 constant dead band space between channel waveforms. The configuration of the
 CorePWM instance in the hardware design must enable the shadow update register
 for each PWM channel that requires synchronous output waveform updates. When the
 shadow register is enabled, the PWM_set_duty_cycle(), PWM_set_edges() and
 PWM_generate_aligned_wave() functions set the new output waveform edge values in
 the channel抯 shadow register instead of directly in the edge registers. Then, a
 call to the PWM_enable_synch_update() function updates the PWM channel抯 output
 waveform at the beginning of the next PWM period. Finally, a call to the
 PWM_disable_synch_update() function completes the update cycle.

 Note: The PWM_enable_synch_update() and PWM_disable_synch_update() functions have
 no affect on any PWM channels that do not have their shadow update registers
 configured in hardware; these channels are always updated immediately,
 asynchronous to the PWM period.

 Note: The pos_edge and neg_edge values passed to the PWM_set_edges() function,
 and the duty_cycle value passed to the PWM_set_duty_cycle() and
 PWM_generate_aligned_wave() functions, may not have the desired effect if
 fixed values were selected for the positive or negative edge registers in
 the hardware configuration of CorePWM.

 A typical sequence of function calls for PWM outputs is:
 a call to function PWM_init() to initialize the CorePWM instance and pass it
 values for the prescale and period; a call to either PWM_set_duty_cycle() or
 PWM_set_edges() , or PWM_generate_aligned_wave() for each PWM output to specify
 the output waveform; a call to PWM_enable() to enable a PWM output; and a call to
 PWM_disable() to disable a PWM output.The function PWM_set_duty_cycle() and
 PWM_generate_aligned_wave() will also enable the PWM output if it is not already
 enabled.

 Tachometer Control
 CorePWM also provides a tachometer interface. During the hardware design, the
 CorePWM configuration mode should be set to either 1 - (PWM and TACH mode) or
 2 - (TACH only mode) which enables the tachometer interface. Each CorePWM hardware
 instance supports up to 16 tachometer inputs.
 The CorePWM tachometer is initialized through a call to the PWM_tach_init() function.
 The PWM_tach_init() function should be called before any other CorePWM driver
 tachometer functions to set up the tachometer prescale value, initialize the
 measurement mode and disable interrupts.
 The PWM_tach_set_mode() function is used to configure the tachometer input channels
 for continuous or one time measurement of the input signal period. The
 PWM_tach_clear_status() and PWM_tach_read_status() functions are used to clear and
 read the measurement status bits for the tachometer input channels. When the status
 bit indicates that a new input signal period measurement is available, the
 PWM_tach_read_value() function is used to read the measured signal period value.

 A typical sequence of function calls for measurement of a tachometer input signal is:
 a call to function PWM_init() to initialize the CorePWM instance and pass it values
 for the prescale and period; a call to PWM_tach_init() to initialize a tachometer
 input and pass it a tachometer prescale value; a call to PWM_tach_set_mode() to set
 the tachometer measurement mode; next a call to PWM_tach_enable_irq(), if interrupts
 are required; then a call to PWM_enable_stretch_pulse() to enable pulse stretching of
 the PWM output; a call to PWM_tach_clear_status() to trigger new measurement of the
 tachometer input signal period; a call to PWM_tach_read_status(), if interrupts are
 not used, to verify that input period value has been updated in the TACHPULSEDUR
 register; now a call to PWM_tach_read_value() to read the measured period of tachometer
 input signal; and finally a call to PWM_disable_stretch_pulse() to disable pulse
 stretching of the PWM output and resume a previously programmed PWM output waveform
 pattern.

 Interrupt Control
 Interrupts generated by CorePWM tachometer status changes are controlled using the
 following functions:
 - PWM_tach_enable_irq()
 - PWM_tach_disable_irq()
 - PWM_tach_clear_irq()
 - PWM_tach_get_irq_source()
 The PWM_tach_get_irq_source() function is used identify which CorePWM tachometer
 input channel has generated an interrupt, among all the tachometer input channels
 that have interrupts enabled.

 *//*=========================================================================*/
#ifndef CORE_PWM_H_
#define CORE_PWM_H_

#include "../../hal/CortexM3/GNU/cpu_types.h"

#ifdef __cplusplus
extern "C"
{
#endif

/*-------------------------------------------------------------------------*//**
 Definition for tachometer measurement mode.
 CorePWM allows the tachometer input measurement mode to be configured. The
 following constants are used as an argument to the PWM_tach_set_mode()
 function to specify the tachometer input measurement mode.
 */
#define TACH_CONTINUOUS  0
#define TACH_ONE_SHOT    1

/*-------------------------------------------------------------------------*//**
 PWM identifiers. The identifiers defined in this enumeration are used to
 identify individual PWM outputs. They are used as argument to most CorePWM
 driver functions to identify the PWM controlled by a function call.
 */
typedef enum
{
	PWM_1 = 1,
	PWM_2,
	PWM_3,
	PWM_4,
	PWM_5,
	PWM_6,
	PWM_7,
	PWM_8,
	PWM_9,
	PWM_10,
	PWM_11,
	PWM_12,
	PWM_13,
	PWM_14,
	PWM_15,
	PWM_16
} pwm_id_t;

/*-------------------------------------------------------------------------*//**
 The pwm_tach_id_t type is used to identify individual CorePWM tachometer
 inputs. The inputs are used as an argument to most CorePWM driver functions
 to identify the PWM tachometer input controlled by a function call.
 */
typedef enum
{
	PWM_TACH_INVALID = 0,
	PWM_TACH_1,
	PWM_TACH_2,
	PWM_TACH_3,
	PWM_TACH_4,
	PWM_TACH_5,
	PWM_TACH_6,
	PWM_TACH_7,
	PWM_TACH_8,
	PWM_TACH_9,
	PWM_TACH_10,
	PWM_TACH_11,
	PWM_TACH_12,
	PWM_TACH_13,
	PWM_TACH_14,
	PWM_TACH_15,
	PWM_TACH_16
} pwm_tach_id_t;

/*-------------------------------------------------------------------------*//**
 The pwm_wave_align_t type is used to align the duty cycle of the PWM output
 waveform within the period of the PWM output waveform. A value of this type
 is used as an argument to the PWM_generate_aligned_wave() function.

 Note: The duty cycle corresponds to the number of period ticks for which
 the PWM output will remain high.
 */
typedef enum
{
	PWM_LEFT_ALIGN, PWM_CENTER_ALIGN, PWM_RIGHT_ALIGN
} pwm_wave_align_t;

/*-------------------------------------------------------------------------*//**
 The pwm_tach_prescale_t type is used to select the PCLK prescale divisor for
 the CorePWM tachometer. A value of this type is used as an argument to the
 PWM_tach_init() function.
 */
typedef enum pwm_tach_prescale
{
	TACH_PRESCALE_PCLK_DIV_1 = 0x0000,
	TACH_PRESCALE_PCLK_DIV_2 = 0x0001,
	TACH_PRESCALE_PCLK_DIV_4 = 0x0002,
	TACH_PRESCALE_PCLK_DIV_8 = 0x0003,
	TACH_PRESCALE_PCLK_DIV_16 = 0x0004,
	TACH_PRESCALE_PCLK_DIV_32 = 0x0005,
	TACH_PRESCALE_PCLK_DIV_64 = 0x0006,
	TACH_PRESCALE_PCLK_DIV_128 = 0x0007,
	TACH_PRESCALE_PCLK_DIV_256 = 0x0008,
	TACH_PRESCALE_PCLK_DIV_512 = 0x0009,
	TACH_PRESCALE_PCLK_DIV_1024 = 0x000A,
	TACH_PRESCALE_PCLK_DIV_2048 = 0x000B
} pwm_tach_prescale_t;

/*-------------------------------------------------------------------------*//**
 This structure is used to identify the various CorePWM hardware instances in
 your system. Your application software should declare one instance of this
 structure for each instance of CorePWM in your system. The function PWM_init()
 Initializes this structure. A pointer to an initialized instance of the
 structure should be passed as the first parameter to the CorePWM driver
 functions, to identify which CorePWM hardware instance should perform the
 requested operation.
 */
typedef struct pwm_instance
{
	addr_t address;
} pwm_instance_t;

/*-------------------------------------------------------------------------*//**
 The PWM_init() function initializes a CorePWM hardware instance and the
 data structure associated with the CorePWM hardware instance. It disables
 all PWM outputs and sets the prescale and period value for the PWM. This
 function should be called before any other CorePWM driver functions.

 @param pwm_inst
 Pointer to a PWM_instance_t structure holding all relevant data associated
 with the target CorePWM hardware instance. This pointer will be used to
 identify the target CorePWM hardware instance in subsequent calls to the
 CorePWM functions.

 @param base_addr
 The base_address parameter is the base address in the processor's memory map
 for the registers of the CorePWM hardware instance being initialized.

 @param prescale
 The prescale parameter is used to specify the PWM period count time base.
 It specifies the PWM granularity.
 The value of this parameter should be between 0 and (2^APB_DWIDTH - 1) where
 APB_DWIDTH is the value selected for the APB_DWIDTH in the instantiation of
 the CorePWM DirectCore hardware instance.
 PWM_GRANULARITY = system_clock_period * (prescale + 1)

 @param period
 The period parameter specifies the period of the PWM cycles.
 The value of this parameter should be between 1 and (2^APB_DWIDTH - 1) where
 APB_DWIDTH is the value selected for the APB_DWIDTH in the instantiation of
 the CorePWM DirectCore hardware instance.
 PWM_PERIOD = PWM_GRANULARITY * (period + 1)

 @return          none.

 Example:
 @code
 #define COREPWM_BASE_ADDR  0xC0000000
 #define PWM_PRESCALE       0
 #define PWM_PERIOD         10

 pwm_instance_t the_pwm;

 void system_init( void )
 {
 PWM_init( &the_pwm, COREPWM_BASE_ADDR, PWM_PRESCALE, PWM_PERIOD ) ;
 }
 @endcode
 */
void PWM_init(pwm_instance_t * pwm_inst, addr_t base_addr, uint32_t prescale,
		uint32_t period);
/*-------------------------------------------------------------------------*//**
 The PWM_enable() function enables the specified PWM output.

 @param pwm_inst
 Pointer to a pwm_inst structure holding all relevant data associated with
 the target CorePWM hardware instance. This pointer is used to identify the
 target CorePWM hardware instance.

 @param pwm_id
 The pwm_id parameter identifies the target PWM output.

 @return
 none.

 Example :
 The following call will enable PWM 1.
 @code
 PWM_enable(&the_pwm, PWM_1);
 @endcode
 */
void PWM_enable(pwm_instance_t * pwm_inst, pwm_id_t pwm_id);

/*-------------------------------------------------------------------------*//**
 The PWM_disable() function disables the specified PWM output.

 @param pwm_inst
 Pointer to a pwm_inst structure holding all relevant data associated with
 the target CorePWM hardware instance. This pointer is used to identify the
 target CorePWM hardware instance.

 @param pwm_id
 The pwm_id parameter identifies the target PWM output.

 @return
 none.

 Example:
 The following call will disable PWM 1.
 @code
 PWM_disable(&the_pwm, PWM_1);
 @endcode
 */
void PWM_disable(pwm_instance_t * pwm_inst, pwm_id_t pwm_id);

/*-------------------------------------------------------------------------*//**
 The PWM_enable_synch_update() function enables synchronous update of PWM
 outputs. In synchronous mode, a selected group of PWM outputs are updated
 at the beginning of the PWM period, which is useful for motor control and
 can be used to keep a constant dead band space between output waveforms.
 Configuration updates for all of the selected PWM outputs are synchronized
 to the beginning of the PWM period, allowing precise updates and maintaining
 phase alignments between outputs.

 Note: The configuration of the CorePWM instance in the hardware design must
 enable the shadow update register for each PWM channel that requires
 synchronous output waveform updates. This function has no affect on any
 PWM channel that does not have its shadow update register configured in
 hardware.

 Note: The PWM_set_duty_cycle(), PWM_set_edges() or PWM_generate_aligned_wave()
 functions must be called to set the new output waveform edge values in
 the channel抯 shadow register before using a call to the
 PWM_enable_synch_update() function to enable the update.

 @param pwm_inst
 Pointer to a pwm_inst structure holding all relevant data associated with
 the target CorePWM hardware instance. This pointer is used to identify the
 target CorePWM hardware instance.

 @return
 none.

 Example:
 Enable synchronous update of the duty cycle for the PWM 1 and PWM 2 outputs.
 @code
 uint32_t duty_cycle = 2;
 PWM_set_duty_cycle( &the_pwm, PWM_1, duty_cycle );
 PWM_set_duty_cycle( &the_pwm, PWM_2, duty_cycle );
 PWM_enable_synch_update( &the_pwm );
 wait_more_than_one_period();
 PWM_disable_synch_update( &the_pwm );
 @endcode
 */
void PWM_enable_synch_update(pwm_instance_t * pwm_inst);

/*-------------------------------------------------------------------------*//**
 The PWM_disable_synch_update() function disables synchronous update of PWM
 outputs. The PWM_disable_synch_update() is used to terminate a synchronous
 update cycle after at least one PWM period has elapsed.

 Note: The configuration of the CorePWM instance in the hardware design must
 enable the shadow update register for each PWM channel that requires
 synchronous output waveform updates. This function has no affect on
 any PWM channel that does not have its shadow update register
 configured in hardware.

 @param pwm_inst
 Pointer to a pwm_inst structure holding all relevant data associated with
 the target CorePWM hardware instance. This pointer is used to identify the
 target CorePWM hardware instance.

 @return
 none.

 Example:
 The call to PWM_disable_synch_update() below will disable synchronous
 update of PWM outputs.
 @code
 PWM_enable_synch_update( &the_pwm );
 wait_more_than_one_period();
 PWM_disable_synch_update(&the_pwm);
 @endcode
 */
void PWM_disable_synch_update(pwm_instance_t * pwm_inst);

/*-------------------------------------------------------------------------*//**
 The PWM_set_duty_cycle() function is used for setting the duty cycle of a
 PWM output.

 Note: It will also enable the PWM output if it is not already enabled.

 @param pwm_inst
 Pointer to a pwm_inst structure holding all relevant data associated with
 the target CorePWM hardware instance. This pointer is used to identify the
 target CorePWM hardware instance.

 @param pwm_id
 The pwm_id parameter identifies the target PWM output.

 @param duty_cycle
 The duty_cycle parameter specifies the PWM output duty cycle.
 In General Purpose PWM mode:
 This parameter corresponds to the number of period ticks for which
 the PWM output will remain high. The value of this parameter should be
 between 0 and the value of the period selected for the call to PWM_init().

 In Low Ripple DAC mode:
 This parameter corresponds to the average density duty cycle. The value
 of this parameter should be between 0 and (2^APB_DWIDTH - 1) where
 APB_DWIDTH  is the value selected for the APB_DWIDTH in the instantiation
 of the CorePWM DirectCore hardware instance. This sets the average
 density of the PWM output high pulses to between 0% and 100% in proportion
 to the duty_cycle value as a percentage of the (2^APB_DWIDTH - 1) value.

 Note: The only role that prescale and period play in Low Ripple DAC mode is
 to set the point when synchronized register updates will take place,
 if the shadow register is enabled for a PWM output.

 @return
 none.

 Example:
 The following example sets the duty cycle of PWM 1 to the value 2.
 @code
 uint32_t duty_cycle = 2;
 PWM_set_duty_cycle( &the_pwm, PWM_1, duty_cycle );

 @endcode
 */
void PWM_set_duty_cycle(pwm_instance_t * pwm_inst, pwm_id_t pwm_id,
		uint32_t duty_cycle);

/*-------------------------------------------------------------------------*//**
 The PWM_set_edges() function is used to configure the positive and negative
 edge of the specified PWM output. The PWM output waveform is controlled by
 specifying the value of period counter at which the output will rise and fall.

 Note: The PWM_set_edges() function does not enable the PWM output. You must
 call the PWM_enable() function to enable the PWM output, either before
 or after calling the PWM_set_edges() function.

 Note: If you specify the same value for both the positive edge and the
 negative edge, this will set the PWM output waveform to toggle mode
 (50% duty cycle). The PWM output waveform will toggle high or low in
 each succeeding PWM period when the period counter reaches the edge
 value set by this function.

 Note: The PWM_get_duty_cycle() function will return the value 0 when it is
 called after using the PWM_set_edges() function to set the PWM output
 waveform to toggle mode (50% duty cycle). A return value of 0 from the
 PWM_get_duty_cycle() function normally means a 0% duty cycle, therefore
 you must be alert to this exception if you use the PWM_set_edges()
 function to manipulate the PWM output waveform edges.

 @param pwm_inst
 Pointer to a pwm_inst structure holding all relevant data associated with
 the target CorePWM hardware instance. This pointer is used to identify
 the target CorePWM hardware instance.

 @param pwm_id
 The pwm_id parameter identifies the target PWM output.

 @param pos_edge
 The pos_edge parameter specifies the value of the period counter at which
 the PWM output identified by pwm_id will rise from low to high. The value
 of this parameter should be between 0 and the value of the period selected
 for the call to PWM_init().

 @param neg_edge
 The neg_edge parameter specifies the value of the period counter at which
 the PWM output identified by pwm_id will fall from high to low. The value
 of this parameter should be between 0 and the value of the period selected
 for the call to PWM_init().

 @return
 none.

 Example:
 The following example sets the positive and negative edges of PWM 1 to 0
 and 2 respectively.
 @code
 uint32_t pos_edge = 0;
 uint32_t neg_edge = 2;
 PWM_set_edges( &the_pwm, PWM_1, pos_edge, neg_edge );

 @endcode
 */
void PWM_set_edges(pwm_instance_t * pwm_inst, pwm_id_t pwm_id,
		uint32_t pos_edge, uint32_t neg_edge);

/*-------------------------------------------------------------------------*//**
 The PWM_get_duty_cycle() function returns the current duty cycle of the
 specified PWM output. The duty cycle corresponds to the number of period
 ticks during which the output remains high and should be between 0 and the
 value of the period selected for the call to PWM_init().

 Note: Duty Cycle (in %) can be calculated as follows:
 Duty Cycle (%) = ( (returned duty cycle value) / (period +1) )*100

 Note: The PWM_get_duty_cycle() function is intended to return the duty cycle
 previously set through calls to the PWM_set_duty_cycle() or
 PWM_generate_aligned_wave() functions.

 Note: A returned duty cycle value of 0 normally means a 0% duty cycle. However,
 the PWM_get_duty_cycle() function will also return the value 0 when it
 is called after using the PWM_set_edges() function to set the PWM output
 waveform to toggle mode. In this case a return value of 0 does not mean
 a 0% duty cycle; rather it means that the PWM output waveform is in
 toggle mode. Refer to the description of the PWM_set_edges() function
 for a description of toggle mode. You must be alert to this exception if
 you use the PWM_set_edges() function to manipulate the PWM output
 waveform edges.

 @param pwm_inst
 Pointer to a pwm_inst structure holding all relevant data associated with
 the target CorePWM hardware instance. This pointer is used to identify the
 target CorePWM hardware instance.

 @param pwm_id
 The pwm_id parameter identifies the target PWM output.

 @return
 This function returns the duty cycle of the PWM output as a 32 bit unsigned
 integer. The duty cycle is the number of period ticks during which the
 output is high.

 Note: A returned duty cycle value of 0 normally means the PWM output is
 constantly low, however it may also indicate that the PWM output
 waveform is set to toggle mode (50% duty cycle). Refer to the note
 in the function description.

 Example:
 Read and assigns current duty cycle value to a variable.
 @code
 uint32_t duty_cycle ;
 duty_cycle = PWM_get_duty_cycle( &the_pwm, PWM_1 );

 @endcode
 */
uint32_t PWM_get_duty_cycle(pwm_instance_t * pwm_inst, pwm_id_t pwm_id);

/*-------------------------------------------------------------------------*//**
 The PWM_generate_aligned_wave() function is used to align the duty_cycle of
 the PWM output waveform within the period of the PWM output waveform.
 Three PWM output waveform alignment options are supported:
 Left Aligned Waveform
 Center Aligned Waveform
 Right Aligned Waveform
 The PWM_generate_aligned_wave() function sets the appropriate positive edge
 and negative edge values to achieve the specified alignment for the PWM output
 waveform.
 Note: It will also enable the PWM output if it is not already enabled.

 The diagram below shows the possible waveform alignments:
 Assume PWM Prescale = 0, so that PWM Period granularity = clock period.
 Each dash & hyphen in this diagram represents one clock period.
 PWM Period = 13. Duty_cycle = 4.


 |<-------- Period ------> |
 _ _ _ _                     _ _ _ _
 |       |                   |       |
 _ _ _|       |_ _ _ _ _ _ _ _ _ _|       |_ _ _
 0       4                   0
 |-- |---|
 V
 Duty Cycle
 _ _ _ _                     _ _ _ _
 |       |                   |       |    --> Left Aligned Waveform
 _ _ _|       |_ _ _ _ _ _ _ _ _ _|       |_ _ _
 0       4                   0
 |           _ _ _ _         |
 |          |       |        |            --> Center Aligned Waveform
 _ _ _|_ _ _ _ _ |       |_ _ _ _ |_ _ _ _ _ _ _
 0          5       9        0
 _ _ _ _|
 |       |            --> Right Aligned Waveform
 _ _ _ _ _ _ _ _ _ _ _ _ _|       |_ _ _ _ _ _ _
 0                   10      0

 @param pwm_inst
 Pointer to a pwm_inst structure holding all relevant data associated with
 the target CorePWM hardware instance. This pointer is used to identify the
 target CorePWM hardware instance.

 @param pwm_id
 The pwm_id parameter identifies the target PWM output.

 @param duty_cycle
 The duty_cycle parameter specifies the PWM output duty cycle. The duty
 cycle corresponds to the number of period ticks for which the PWM output
 will remain high. The value of this parameter should be between 0 and
 the value of the period selected for the call to PWM_init().

 @param alignment_type
 The alignment_type parameter specifies required alignment for the PWM
 output waveform. Allowed values of type pwm_wave_align_t are:
 PWM_LEFT_ALIGN
 PWM_CENTER_ALIGN
 PWM_RIGHT_ALIGN

 @return
 none.

 Example:
 The following example sets up PWM channels 1, 2 and 3 to generate left, center
 and right aligned output waveforms respectively.
 @code
 PWM_generate_aligned_wave(&the_pwm, PWM_1, duty_cycle, LEFT_ALIGN);
 PWM_generate_aligned_wave(&the_pwm, PWM_2, duty_cycle, CENTER_ALIGN);
 PWM_generate_aligned_wave(&the_pwm, PWM_3, duty_cycle, RIGHT_ALIGN);
 @endcode
 */
void PWM_generate_aligned_wave(pwm_instance_t * pwm_inst, pwm_id_t pwm_id,
		uint32_t duty_cycle, pwm_wave_align_t alignment_type);

/*-------------------------------------------------------------------------*//**
 The PWM_enable_stretch_pulse() function is used to enable pulse stretching
 for the specified PWM output. To accurately measure the speed of 3-wire fans,
 it is necessary to turn on the fan periodically for long enough to get a
 complete measurement of the tachometer signal from the fan. This stretching
 of the PWM output pulse for a long duration is referred as PWM pulse
 stretching. When pulse stretching is enabled, the PWM output is set to high
 or low, dependent upon the configuration of the CorePWM instance in the
 hardware design. The PWM_disable_stretch_pulse() function must be used to
 disable PWM pulse stretching once the fan speed measurement is completed.

 Note: The configuration of the CorePWM instance in the hardware design must
 select the PWM output level � high or low � that is set when PWM pulse
 stretching is enabled. For example, to measure 3- wire fan speed, the
 CorePWM hardware configuration should select a high stretch level for
 the PWM output.

 @param pwm_inst
 Pointer to a pwm_inst structure holding all relevant data associated with
 the target CorePWM hardware instance. This pointer is used to identify the
 target CorePWM hardware instance.

 @param pwm_id
 The pwm_id parameter identifies the target PWM output.

 @return
 none.

 Example:
 The following function call enables the stretching of PWM output 1 pulse for
 tachometer input measurement.
 @code
 PWM_enable_stretch_pulse(&the_pwm, PWM_1);
 @endcode
 */
void PWM_enable_stretch_pulse(pwm_instance_t * pwm_inst, pwm_id_t pwm_id);

/*-------------------------------------------------------------------------*//**
 The PWM_disable_stretch_pulse() function is used to disable pulse stretching
 for the specified PWM output. This function must be called once your
 application has completed the measurement of the tachometer input. When pulse
 stretching is disabled, the PWM output resumes generation of its previously
 programmed output waveform pattern.

 @param pwm_inst
 Pointer to a pwm_inst structure holding all relevant data associated with
 the target CorePWM hardware instance. This pointer is used to identify the
 target CorePWM hardware instance.

 @param pwm_id
 The pwm_id parameter identifies the target PWM output.

 @return
 none.

 Example:
 The following function call disables the stretching of the PWM 1 output
 pulse after completing the tachometer input measurement.
 @code
 PWM_disable_stretch_pulse(&the_pwm, PWM_1);
 @endcode
 */
void PWM_disable_stretch_pulse(pwm_instance_t * pwm_inst, pwm_id_t pwm_id);

/*-------------------------------------------------------------------------*//**
 The PWM_tach_init() function is used to initialize the configuration of
 all of the CorePWM tachometer inputs. It sets the tachometer抯 TACHPRESCALE
 register to the value specified by the tach_prescale parameter. It sets the
 tachometer measurement mode to continuous measurement for all tachometer
 inputs. It disables the interrupts for all tachometer inputs and clears any
 pending interrupts.

 Note: This function should be called before any other CorePWM driver
 tachometer functions.

 @param pwm_inst
 Pointer to a pwm_inst structure holding all relevant data associated with
 the target CorePWM hardware instance. This pointer is used to identify the
 target CorePWM hardware instance.

 @param tach_prescale
 The tach_prescale value is used to select the PCLK prescale divisor for the
 CorePWM tachometer. This determines the period counter time base for
 tachometer measurements. Allowed values of type pwm_tach_prescale_t are:
 TACH_PRESCALE_PCLK_DIV_1
 TACH_PRESCALE_PCLK_DIV_2
 TACH_PRESCALE_PCLK_DIV_4
 TACH_PRESCALE_PCLK_DIV_8
 TACH_PRESCALE_PCLK_DIV_16
 TACH_PRESCALE_PCLK_DIV_32
 TACH_PRESCALE_PCLK_DIV_64
 TACH_PRESCALE_PCLK_DIV_128
 TACH_PRESCALE_PCLK_DIV_256
 TACH_PRESCALE_PCLK_DIV_512
 TACH_PRESCALE_PCLK_DIV_1024
 TACH_PRESCALE_PCLK_DIV_2048

 @return
 none.

 Example:
 The following call to PWM_tach_init() initializes the CorePWM tachometer and
 sets the PCLK prescale divisor to 8 for tachometer measurements.
 @code
 pwm_tach_prescale_t tach_prescale = TACH_PRESCALE_PCLK_DIV_8;
 PWM_tach_init(&the_pwm, tach_prescale);
 @endcode

 */
void PWM_tach_init(pwm_instance_t *pwm_inst, pwm_tach_prescale_t tach_prescale);

/*-------------------------------------------------------------------------*//**
 The PWM_tach_set_mode() function sets the measurement mode for the
 specified tachometer input. This function selects how frequently the
 tachometer input should be measured. There are two options for the measurement
 mode:
 Continuous measurement of tachometer input
 One time measurement of tachometer input

 @param pwm_inst
 Pointer to a pwm_inst structure holding all relevant data associated with
 the target CorePWM hardware instance. This pointer is used to identify the
 target CorePWM hardware instance.

 @param pwm_tach_id
 The pwm_tach_id parameter identifies the target tachometer input.

 @param pwm_tachmode
 The pwm_tachmode parameter is used to specify the tachometer input
 measurement mode. Allowed values for pwm_tachmode are:
 TACH_CONTINUOUS
 TACH_ONE_SHOT

 @return
 none.

 Example:
 The following example sets up tachometer input 1 for one time measurement.
 @code
 PWM_tach_set_mode(&the_pwm, PWM_TACH_1,TACH_ONE_SHOT);
 @endcode
 */
void PWM_tach_set_mode(pwm_instance_t * pwm_inst, pwm_tach_id_t pwm_tach_id,
		uint16_t pwm_tachmode);

/*-------------------------------------------------------------------------*//**
 The PWM_tach_read_value() function reads the measured period of the
 tachometer input signal from the TACHPULSEDUR register corresponding to
 the specified tachometer input. The value returned is the number of timer
 ticks between two successive positive (or negative) edges of the tachometer
 input signal.

 @param pwm_inst
 Pointer to a pwm_inst structure holding all relevant data associated with
 the target CorePWM hardware instance. This pointer is used to identify the
 target CorePWM hardware instance.

 @param pwm_tach_id
 The pwm_tach_id parameter identifies the target tachometer input.

 @return
 It returns the number of timer ticks between two successive positive
 (or negative) edges of the tachometer input signal as a 16 bit unsigned
 integer.

 Example:
 Read and assign the value of the current period measurement for tachometer
 input 1 to a variable.
 @code
 uint16_t tach_input_value ;
 tach_input_value = PWM_tach_read_value(&the_pwm, PWM_TACH_1);
 @endcode
 */
uint16_t PWM_tach_read_value(pwm_instance_t * pwm_inst,
		pwm_tach_id_t pwm_tach_id);

/*-------------------------------------------------------------------------*//**
 The PWM_tach_clear_status() function is used to clear the tachometer
 status bit for the specified tachometer input. This allows the tachometer
 to take a new measurement of the input signal period and store it in the
 TACHPULSEDUR register corresponding to the specified tachometer input. This
 function is typically called when the user want to take a new reading of
 the tachometer input signal period.

 @param pwm_inst
 Pointer to a pwm_inst structure holding all relevant data associated with
 the target CorePWM hardware instance. This pointer is used to identify the
 target CorePWM hardware instance.

 @param pwm_tach_id
 The pwm_tach_id parameter identifies the target tachometer input.

 @return
 none.

 Example:
 The following call clears the status bit for tachometer input 1 to begin
 a new input period measurement.
 @code
 PWM_tach_clear_status(&the_pwm, PWM_TACH_1);
 @endcode
 */
void PWM_tach_clear_status(pwm_instance_t * pwm_inst,
		pwm_tach_id_t pwm_tach_id);

/*-------------------------------------------------------------------------*//**
 The PWM_tach_read_status() function returns the current status for the
 specified tachometer input. This function returns 1 if the tachometer input
 period measurement has been updated at least once since the status bit was
 cleared,otherwise it returns 0.

 @param pwm_inst
 Pointer to a pwm_inst structure holding all relevant data associated with
 the target CorePWM hardware instance. This pointer is used to identify the
 target CorePWM hardware instance.

 @param pwm_tach_id
 The pwm_tach_id parameter identifies the target tachometer input.

 @return
 It returns 1 if the tachometer input period measurement has been updated
 at least once since the status bit was cleared, otherwise it returns 0.

 Example:
 Read and assign the current status of tachometer input 1 to a variable.
 @code
 uint16_t tach_input_status ;
 tach_input_status = PWM_tach_read_status(&the_pwm, PWM_TACH_1);
 @endcode
 */
uint16_t PWM_tach_read_status(pwm_instance_t * pwm_inst,
		pwm_tach_id_t pwm_tach_id);

/*-------------------------------------------------------------------------*//**
 The PWM_tach_get_irq_source() function is used identify which tachometer
 input channel has generated an interrupt,among all the tachometer input
 channels with interrupts enabled.

 @param pwm_inst
 Pointer to a pwm_inst structure holding all relevant data associated with
 the target CorePWM hardware instance. This pointer is used to identify the
 target CorePWM hardware instance.

 @return
 It returns the pwm_tach_id_t identifier of the tachometer input generating
 the interrupt. It returns 0 if no tachometer input is generating an interrupt.

 Example:
 The following example returns the tachometer 1 identifier, PWM_TACH_1,
 when PWM_tach_get_irq_source() is called, after the tachometer input 1
 period measurement has been completed by CorePWM.
 @code
 pwm_tach_id_t tach_input_no ;
 PWM_tach_enable_irq( &the_pwm, PWM_TACH_1);
 PWM_tach_clear_status( &the_pwm, PWM_TACH_1);
 tach_input_no = PWM_tach_get_irq_source( &the_pwm );
 @endcode
 */
pwm_tach_id_t PWM_tach_get_irq_source(pwm_instance_t * pwm_inst);
/*-------------------------------------------------------------------------*//**
 The PWM_tach_enable_irq() function is used to enable interrupt generation
 for the specified tachometer input channel.

 Note: CorePWM asserts its interrupt output signal, when a tachometer input
 channel抯 period measurement has been updated at least once since the
 channel抯 interrupt was last cleared, if the channel is enabled for
 interrupt generation.

 @param pwm_inst
 Pointer to a pwm_inst structure holding all relevant data associated with
 the target CorePWM hardware instance. This pointer is used to identify the
 target CorePWM hardware instance.

 @param pwm_tach_id
 The pwm_tach_id parameter identifies the target tachometer input.

 @return
 none.

 Example:
 This call to PWM_tach_enable_irq() allows tachometer input 1 to generate an
 interrupt, when its input signal period measurement value is updated.
 @code
 PWM_tach_enable_irq(&the_pwm, PWM_TACH_1);
 @endcode
 */
void PWM_tach_enable_irq(pwm_instance_t * pwm_inst, pwm_tach_id_t pwm_tach_id);

/*-------------------------------------------------------------------------*//**
 The PWM_tach_disable_irq() function is used to disable interrupt generation
 for the specified tachometer input channel.

 @param pwm_inst
 Pointer to a pwm_inst structure holding all relevant data associated with
 the target CorePWM hardware instance. This pointer is used to identify the
 target CorePWM hardware instance.

 @param pwm_tach_id
 The pwm_tach_id parameter identifies the target tachometer input.

 @return
 none.

 Example:
 This call to PWM_tach_disable_irq() will prevent tachometer input 1 from
 generating an interrupt when its input signal period measurement value is
 updated.
 @code
 PWM_tach_disable_irq(&the_pwm, PWM_TACH_1);
 @endcode
 */
void PWM_tach_disable_irq(pwm_instance_t * pwm_inst, pwm_tach_id_t pwm_tach_id);

/*-------------------------------------------------------------------------*//**
 The PWM_tach_clear_irq() function is used to clear a pending interrupt
 generated by the specified tachometer input channel.

 Note: The PWM_tach_clear_irq() function  must be called as part of a PWM
 tachometer interrupt service routine (ISR) in order to prevent the
 same interrupt event retriggering a call to the PWM tachometer ISR.

 Note: Interrupts may also need to be cleared in the processor's interrupt
 controller.

 @param pwm_inst
 Pointer to a pwm_inst structure holding all relevant data associated with
 the target CorePWM hardware instance. This pointer is used to identify the
 target CorePWM hardware instance.

 @param pwm_tach_id
 The pwm_tach_id parameter identifies the target tachometer input.

 @return
 none.

 Example:
 This call to PWM_tach_clear_irq() will clear a pending interrupt from tachometer
 input 1.
 @code
 PWM_tach_clear_irq(&the_pwm, PWM_TACH_1);
 @endcode
 */
void PWM_tach_clear_irq(pwm_instance_t * pwm_inst, pwm_tach_id_t pwm_tach_id);

/** @} */

#ifdef __cplusplus
}
#endif

#endif /*CORE_PWM_H_*/
